package org.ytor.core.sqlflow.builder;

import org.ytor.common.classmeta.ClassMetadata;
import org.ytor.common.exception.BaseException;
import org.ytor.common.util.Strs;
import org.ytor.common.util.cache.ClassCache;
import org.ytor.core.sqlflow.SFunction;
import org.ytor.core.sqlflow.anno.Table;

import java.lang.invoke.SerializedLambda;
import java.util.HashMap;
import java.util.Map;

/**
 * created by yangtong on 2025/8/8 11:15:04
 * <br/>
 * sql 各个子句构建器
 */
public abstract class AbsBuilder implements ISQL {

    /**
     * 表别名映射
     */
    protected Map<Object, String> tableAliases = new HashMap<>();

    protected <T> String resolveField(SFunction<T, ?> fn) {
        try {
            SerializedLambda lambda = fn.parse();
            String className = resolveRealClassName(lambda);
            if (className == null) {
                className = lambda.getImplClass().replace("/", ".");
            }
            // 反射获取类型
            Class<?> clazz = Class.forName(className);
            String methodName = lambda.getImplMethodName();
            String alias = tableAliases.getOrDefault(clazz, Strs.toUnderline(clazz.getSimpleName()));
            return Strs.format("{}.{}", alias, parseMethodToField(methodName));
        } catch (Exception e) {
            throw new BaseException("字段解析失败", e);
        }
    }

    protected static String parseMethodToField(String methodName) {
        if (methodName == null) {
            throw new BaseException("方法名称不能为空！");
        }
        if (methodName.startsWith("get")) {

            return Strs.toUnderline(methodName.substring(3));
        } else if (methodName.startsWith("is")) {
            return Strs.toUnderline(methodName.substring(2));
        }
        return methodName;
    }

    /**
     * 根据class获取表名称
     */
    protected static String getTableName(Class<?> clazz) {
        ClassMetadata<?> classMetadata = ClassCache.get(clazz);
        Table tableAnno = classMetadata.getAnnotation(Table.class);
        if (tableAnno != null) {
            return tableAnno.value();
        }
        return Strs.toUnderline(clazz.getSimpleName());
    }

    private String resolveRealClassName(SerializedLambda lambda) {
        String mt = lambda.getInstantiatedMethodType();
        int start = mt.indexOf('L');
        int end = mt.indexOf(';', start);
        if (start >= 0 && end > 1) {
            return mt.substring(start + 1, end).replace('/', '.');
        }
        return null;
    }
}
